#ifndef SPW_TYPE_TRAITS_H_
#define SPW_TYPE_TRAITS_H_
#include <spw_config.h>
namespace spwstd{
namespace spwtraits{

// # 模板
// ## enable_if
// 如果判别式为ture有指定类型，为false类型未定义，会忽略该函数模板
template<bool, typename VT = void>
struct Enable_If {};
template<typename VT>
struct Enable_If<true, VT> { using type = VT; };


// ## conditional
template<bool Cond, typename Ifture, typename Iffalse>
struct Conditional { using type = Ifture; };
template<typename Ifture, typename Iffalse>
struct Conditional<false, Ifture, Iffalse> { using type = Iffalse; };

// ## declval
// 正常情况
template<typename T, typename U = T&&>
U Declval_in(int);

// 如果T为void, 因为void&&不存在，是语法错误，所以会匹配到该模板
template<typename T>
T Declval_in(long);

// 把T转换成T&&
// 不需要T实际构造
template<typename T>
auto Declval() noexcept -> decltype(Declval_in<T>(0));

// # 包装特定类型的静态常量基类
template<typename ValueT, ValueT v>
struct Intergral_Constant_in {
    static constexpr ValueT   value = v;
    using value_type = ValueT;
    using type = Intergral_Constant_in<ValueT, v>;
    // 返回包裹的值
    // 转换函数, 可以隐式类型intergal_constant转换成value_type
    constexpr operator value_type() const { return value; }
    constexpr value_type operator()() const { return value; }
};

// ## 获得一个值的静态变量
template<typename ValueT, ValueT v>
constexpr ValueT Intergral_Constant_in<ValueT, v>::value;

using true_type=Intergral_Constant_in<bool, true>;
using false_type=Intergral_Constant_in<bool, false>;

// ## 内部使用，元编程的辅助
// ### or
// template<bool, typename, typename>
// struct Conditional;
template<typename...>
struct Or_in;

template<>
struct Or_in<>: public false_type{};

template<typename B>
struct Or_in<B>: public B {};

template<typename B1, typename B2>
struct Or_in<B1, B2>
    : public Conditional<B1::value, B1, B2>::type {};

template<typename B1, typename B2, typename B3, typename... Bn>
struct Or_in<B1, B2, B3, Bn...>
    : public Conditional<B1::value, B1, Or_in<B2,B3,Bn...>>::type {};

// ### and
template<typename...>
struct And_in;

template<>
struct And_in<>: public true_type{};

template<typename B>
struct And_in<B>: public B {};

template<typename B1, typename B2>
struct And_in<B1, B2>
    : public Conditional<B1::value, B2, B1>::type {};

template<typename B1, typename B2, typename B3, typename... Bn>
struct And_in<B1, B2, B3, Bn...>
    : public Conditional<B1::value, And_in<B2,B3,Bn...>, B1>::type {};

// Not_in
template<typename N>
struct Not_in: public Intergral_Constant_in<bool, !N::value> {};

// require
template<typename... Cond>
using Require_in = typename Enable_If<And_in<Cond...>::value>::type;

// # 基础类型类别
// ## class
// 思路：利用类成员指针，有类成员指针为类类别
// 虽然union是特殊struct,但是在该检测中不属于class。但无法实现去除union
template<typename T>
struct Is_Class_helper_in{
    template<typename D>
    static true_type test_in(int D::*);

    template<typename>
    static false_type test_in(...);

    using type = decltype(test_in<T>(nullptr));
};

template<typename T>
struct Is_Class: public Is_Class_helper_in<T>::type {};

// ## empty
// 思路：空继承类sizeof==1则基类为空基类
// 使用Is_Class所以无法辨别union
template<typename T, bool = Is_Class<T>::value>
struct Is_Empty_helper_in {
    class test_in : T{};

    template<typename D, typename spwtraits::Enable_If<sizeof(D)==1, int>::type = 0>
    static true_type test_aux_in(int);

    template<typename D, typename spwtraits::Enable_If<sizeof(D)!=1, int>::type = 0>
    static false_type test_aux_in(int);

    using type = decltype(test_aux_in<test_in>(0));
};

template<typename T>
struct Is_Empty_helper_in<T, false> {
    using type = false_type;
};

template<typename T>
struct Is_Empty: public Is_Empty_helper_in<T>::type{};

// ## is_final

// ## void
template<typename>
struct Remove_Cv;

template<typename>
struct Is_Void_helper_in: public false_type {};

template<>
struct Is_Void_helper_in<void>: public true_type {};

template<typename ValueT>
struct Is_Void : public Is_Void_helper_in<typename Remove_Cv<ValueT>::type>::type {};

// ## integral
template<typename>
struct Is_Integral_Helper_in: public false_type {};

template<>
struct Is_Integral_Helper_in<bool>: public true_type {};

template<>
struct Is_Integral_Helper_in<char>: public true_type {};

template<>
struct Is_Integral_Helper_in<signed char>: public true_type {};

template<>
struct Is_Integral_Helper_in<unsigned char>: public true_type {};

template<>
struct Is_Integral_Helper_in<short>: public true_type {};

template<>
struct Is_Integral_Helper_in<unsigned short>: public true_type {};

template<>
struct Is_Integral_Helper_in<int>: public true_type {};

template<>
struct Is_Integral_Helper_in<unsigned int>: public true_type {};

template<>
struct Is_Integral_Helper_in<long>: public true_type {};

template<>
struct Is_Integral_Helper_in<unsigned long>: public true_type {};

template<>
struct Is_Integral_Helper_in<long long>: public true_type {};

template<>
struct Is_Integral_Helper_in<unsigned long long>: public true_type {};

template<typename ValueT>
struct Is_Integral: public Is_Integral_Helper_in<typename Remove_Cv<ValueT>::type>::type {};

// ## float浮点
template<typename>
struct Is_Floating_Point_Helper_in: public false_type {};

template<>
struct Is_Floating_Point_Helper_in<float>: public true_type {};

template<>
struct Is_Floating_Point_Helper_in<double>: public true_type {};

template<>
struct Is_Floating_Point_Helper_in<long double>: public true_type {};

template<typename ValueT>
struct Is_Floating_Point: Is_Floating_Point_Helper_in<typename Remove_Cv<ValueT>::type>::type {};

// ## point
template<typename>
struct Is_Pointer_Helper_in: public false_type {};

template<typename ValueT>
struct Is_Pointer_Helper_in<ValueT*>: public true_type {};

template<typename ValueT>
struct Is_Pointer: public Is_Pointer_Helper_in<typename Remove_Cv<ValueT>::type>::type {};

// ## array
template<typename>
struct Is_Array: public false_type {};

template<typename T>
struct Is_Array<T[]>: public true_type {};

template<typename T, spwconfig::size_t Size>
struct Is_Array<T[Size]>: public true_type {};

/// is_function
/// c++17 之前 noexpect不是函数声明的一部分，不支持noexpect函数是重载函数
template<typename>
  struct Is_Function
  : public false_type { };
// 通用
template<typename _Res, typename... _ArgTypes>
  struct Is_Function<_Res(_ArgTypes...)>
  : public true_type { };

template<typename _Res, typename... _ArgTypes>
  struct Is_Function<_Res(_ArgTypes...) &>
  : public true_type { };

template<typename _Res, typename... _ArgTypes>
  struct Is_Function<_Res(_ArgTypes...) &&>
  : public true_type { };

// const 
template<typename _Res, typename... _ArgTypes>
  struct Is_Function<_Res(_ArgTypes...) const>
  : public true_type { };

template<typename _Res, typename... _ArgTypes>
  struct Is_Function<_Res(_ArgTypes...) const &>
  : public true_type { };

template<typename _Res, typename... _ArgTypes>
  struct Is_Function<_Res(_ArgTypes...) const &&>
  : public true_type { };

// volatile
template<typename _Res, typename... _ArgTypes>
  struct Is_Function<_Res(_ArgTypes...) volatile>
  : public true_type { };

template<typename _Res, typename... _ArgTypes>
  struct Is_Function<_Res(_ArgTypes...) volatile &>
  : public true_type { };

template<typename _Res, typename... _ArgTypes>
  struct Is_Function<_Res(_ArgTypes...) volatile &&>
  : public true_type { };

// const volatile
template<typename _Res, typename... _ArgTypes>
  struct Is_Function<_Res(_ArgTypes...) const volatile>
  : public true_type { };

template<typename _Res, typename... _ArgTypes>
  struct Is_Function<_Res(_ArgTypes...) const volatile &>
  : public true_type { };

template<typename _Res, typename... _ArgTypes>
  struct Is_Function<_Res(_ArgTypes...) const volatile &&>
  : public true_type { };

// # 类型属性
// ## const
template<typename>
struct Is_Const: public false_type {};

template<typename ValueT>
struct Is_Const<const ValueT>: public true_type {};

// ## volatile
template<typename>
struct Is_Volatile: public false_type {};

template<typename ValueT>
struct Is_Volatile<volatile ValueT>: public true_type {};

// ## lvalue reference
template<typename>
struct Is_Lvalue_Reference: public false_type {};

template<typename TV>
struct Is_Lvalue_Reference<TV&>: public true_type {};

// ## rvalue reference
template<typename>
struct Is_Rvalue_Reference: public false_type {};

template<typename TV>
struct Is_Rvalue_Reference<TV&&>: public true_type {};

// # 类型关系
// ## is_base_of<A,B>
// A类型是B类型的基类或A,B类型相等{但是AB不能为基础类型}，只有类类型使用
// 思路：A，B都为类类型, 并且B*可以隐式转化为A*
// 任何指向类的指针都可以隐式转换成void*
template<typename Base, typename Derived, bool=Is_Class<Base>::value&&Is_Class<Derived>::value >
struct Is_Base_Of_helper_in{
    template<typename T>
    static true_type test_in(const volatile T*);

    template<typename>
    static false_type test_in(const volatile void*);

    template<typename B, typename D>
    static auto test_aux_in(int) ->
        decltype(test_in<B>(static_cast<D*>(nullptr)));

    template<typename, typename>
    static auto test_aux_in(...) -> true_type;

    using type = decltype(test_aux_in<Base, Derived>(0)); 
};

template<typename Base, typename Derived>
struct Is_Base_Of_helper_in<Base, Derived, false>{
    using type = false_type;
};

template<typename Base, typename Derived>
struct Is_Base_Of: Is_Base_Of_helper_in<Base, Derived>::type {};

// ## is_same
template<typename, typename>
struct Is_Same: public false_type {};

template<typename ValueT>
struct Is_Same<ValueT, ValueT>: public true_type {};

// ## is_convertible可转换的
//若虚构函数定义
// To test() { return std::declval<From>(); }
// 为良构，（即 std::declval<From>() 能用隐式转换转换为 To ，
// 或 From 和 To 均为可有 cv 限定的 void ），
// 则提供等于 true 的成员常量 value 。否则 value 为 false 。

// 当bool 为true
// from为void
// 或to为function
// 或to为array
// 当from to都为void类型，为true_type
// 试图转换为functype or arraytype都为错
// void除了转换成void都为错
template<typename From, typename To, 
            bool = Or_in<
                Is_Void<From>, Is_Function<To>, Is_Array<To>
            >::value
        >
struct Is_Convertible_Helper_in{
    using type = typename Is_Void<To>::type;
};

// 当bool为false
template<typename From, typename To>
struct Is_Convertible_Helper_in<From, To, false>
{
private:
    template<typename T>
    static void test_aux_in(T);

    // spwtraits::Declval<F>()能隐式转换成T，
    // spwtraits::Declval<F>()为F&&
    template<typename F, typename T,
            typename = decltype(test_aux_in<T>( spwtraits::Declval<F>() )) >
    static true_type test_in(int);

    template<typename, typename>
    static false_type test_in(...);
public:
    using type = decltype(test_in<From, To>(0));
};

template<typename From, typename To>
struct Is_Convertible
    : public Is_Convertible_Helper_in<From, To>::type {};

// # 类型修改
// ## remove const-volatile 
template<typename ValueT>
struct Remove_Const {
    using type = ValueT;
};

template<typename ValueT>
struct Remove_Const<const ValueT> {
    using type = ValueT;
};

template<typename ValueT>
struct Remove_Volatile {
    using type = ValueT;
};

template<typename ValueT>
struct Remove_Volatile<volatile ValueT> {
    using type = ValueT;
};

template<typename ValueT>
struct Remove_Cv {
    using type = typename Remove_Const<typename Remove_Volatile<ValueT>::type>::type;
};

// ## remove reference
template<typename VT>
struct Remove_Reference { using type = VT; };

template<typename VT>
struct Remove_Reference<VT&> { using type = VT; };

template<typename VT>
struct Remove_Reference<VT&&> { using type = VT; };

// ## remove 数组一个维度 
template<class T>
struct Remove_Extent { using type = T; };
 
template<class T>
struct Remove_Extent<T[]> { using type = T; };
 
template<class T, spwconfig::size_t N>
struct Remove_Extent<T[N]> { using type = T; };

// ## remove point
template<typename T, typename>
struct Remove_Pointer_help_in{
    using type = T;
};

template<typename T, typename U>
struct Remove_Pointer_help_in<T, U*>{
    using type = U;
};

template<typename T>
struct Remove_Pointer: public Remove_Pointer_help_in<T, typename Remove_Cv<T>::type>{};

// ## add
template<typename VT>
struct Add_Const{
    using type = const VT;
};

template<typename VT>
struct Add_Con_ref {
    using type = const VT&;
};

template<typename VT>
struct Add_Con_ref<VT&> {
    using type = const VT&;
};

// replacefirstarg 第一个参数TC为模版类, U替换TC模版的第一个模版参数
template<typename TC, typename U>
struct ReplaceFirstArg {};

template<template<typename, typename...> class Temp, typename U,
    typename T, typename... Types>
struct ReplaceFirstArg<Temp<T, Types...>, U> {
    using type = Temp<U, Types...>;
};

template<typename TC, typename U>
struct Rebind : ReplaceFirstArg<TC, U>{};

// alloc_rebind
template<typename Alloc, typename U>
using AllocRebind = typename Rebind<Alloc, U>::type;

} // namespace spwtraits
} // namespace spwstd
#endif // SPW_TYPE_TRAITS_H_
